//
//  UIPhoneField.swift
//  CommonFoundation
//
//  Created by raniys on 2/1/18.
//  Copyright © 2018 raniys. All rights reserved.
//

import UIKit

/// Format the mobile phone number(string) of Chinese with separator. e.g.: '18231234312' -> '182 3123 4312'
///
/// - Parameters:
///   - number: mobile phone number. e.g.: '18231234312'
///   - separator: separator for split the phone number. e.g.: ' '(blank)
/// - Returns: the splited phone number
public func formatChineseMobileNumber(number: String, separator: String) -> String {
    var result = ""
    
    // only allow number in the string
    let buffer = formatContactsPhoneNumber(number: number)
    for (i, _) in buffer.unicodeScalars.enumerated() {
        // add the separator at index 3 and index 7
        if i == 3 || i == 7 {
            result.append(separator)
        }
        result.append(buffer[i])
    }
    
    return result
}


/// Format the mobile phone number(string) which copied from System Contacts to only allow number in the string. e.g.: "\u{e2}13316853133\u{e2}" -> '13316853133'
///
/// - Parameters:
///   - number: mobile phone number which copied from System Contacts
/// - Returns: the correct phone number
public func formatContactsPhoneNumber(number: String) -> String {
    var buffer = ""
    for (i, char) in number.unicodeScalars.enumerated() {
        guard CharacterSet.decimalDigits.contains(char) else {
            continue
        }
        buffer.append(number[i])
    }
    return buffer
}


public class PhoneField: UITextField {
    
    public var phoneNumber: String? {
        
        guard let string = text else {
            return nil
        }
        
        //处理后的结果字符串
        var result = ""
        
        //遍历每一个字符
        for (i, uni) in string.unicodeScalars.enumerated() {
            //如果是数字则添加到返回结果中
            if CharacterSet.decimalDigits.contains(uni) {
                result.append(string[i])
            }
        }
        
        return result
    }
    
    //保存上一次的文本内容
    var _previousText:String!
    
    //保持上一次的文本范围
    var _previousRange:UITextRange!
    
    
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    
    //当本视图的父类视图改变的时候
    override public func willMove(toSuperview newSuperview: UIView?) {
        //监听值改变通知事件
        if newSuperview != nil {
            NotificationCenter.default.addObserver(self,
                                                   selector: #selector(phoneNumberFormat(_:)),
                                                   name: UITextField.textDidChangeNotification,
                                                   object: nil)
        } else {
            NotificationCenter.default.removeObserver(self,
                                                      name: UITextField.textDidChangeNotification,
                                                      object: nil)
        }
    }
    
    
    public func clearText() {
        text = nil
        _previousText = ""
        _previousRange = self.selectedTextRange
    }
    
    //输入框内容改变时对其内容做格式化处理
    @objc func phoneNumberFormat(_ notification: Notification) {
        let textField = notification.object as! UITextField
        
        if(!textField.isEqual(self)){
            return
        }
        
        //输入的第一个数字必需为1
        if textField.text != "" && (textField.text![0] as NSString).intValue != 1 {
            //第1位输入非1数则使用原来值，且关闭停留在开始位置
            textField.text = _previousText
            let start = textField.beginningOfDocument
            textField.selectedTextRange = textField.textRange(from: start, to: start)
            return
        }
        
        //当前光标的位置（后面会对其做修改）
        var cursorPostion = textField.offset(from: textField.beginningOfDocument,
                                             to: textField.selectedTextRange!.start)
        
        //过滤掉非数字字符，只保留数字
        let digitsText = getDigitsText(string: textField.text!,
                                       cursorPosition: &cursorPostion)
        
        //避免超过11位的输入
        if digitsText.count > 11 {
            textField.text = _previousText
            textField.selectedTextRange = _previousRange
            return
        }
        
        //得到带有分隔符的字符串
        let hyphenText = getHyphenText(string: digitsText, cursorPosition: &cursorPostion)
        
        //将最终带有分隔符的字符串显示到textField上
        textField.text = hyphenText
        
        //让光标停留在正确位置
        let targetPostion = textField.position(from: textField.beginningOfDocument,
                                               offset: cursorPostion)!
        textField.selectedTextRange = textField.textRange(from: targetPostion,
                                                          to: targetPostion)
        
        //现在的值和选中范围，供下一次输入使用
        _previousText = self.text!
        _previousRange = self.selectedTextRange!
    }
    
    //除去非数字字符，同时确定光标正确位置
    func getDigitsText(string:String, cursorPosition:inout Int) -> String{
        //保存开始时光标的位置
        let originalCursorPosition = cursorPosition
        //处理后的结果字符串
        var result = ""
        
        //遍历每一个字符
        for (i, uni) in string.unicodeScalars.enumerated() {
            //如果是数字则添加到返回结果中
            if CharacterSet.decimalDigits.contains(uni) {
                result.append(string[i])
            }
                //非数字则跳过，如果这个非法字符在光标位置之前，则光标需要向前移动
            else{
                if i < originalCursorPosition {
                    cursorPosition = cursorPosition - 1
                }
            }
        }
        
        return result
    }
    
    //将分隔符插入现在的string中，同时确定光标正确位置
    func getHyphenText(string:String, cursorPosition:inout Int) -> String {

        let result = formatChineseMobileNumber(number: string, separator: " ")
        
        if cursorPosition < result.count {
            cursorPosition = result.count
        }
        
        return result
    }
}

//通过对String扩展，字符串增加下表索引功能
extension String
{
    subscript(index:Int) -> String
    {
        get{
            return String(self[self.index(self.startIndex, offsetBy: index)])
        }
        set{
            let tmp = self
            self = ""
            for (idx, item) in tmp.enumerated() {
                if idx == index {
                    self += "\(newValue)"
                }else{
                    self += "\(item)"
                }
            }
        }
    }
}
